<html>
<head>
  <script src="../OLLoader.js"></script>
  <script type="text/javascript">

    function test_Class(t) {
        t.plan(1);
        var MyClass = OpenLayers.Class({
            initialize: function () {
                t.ok(false, "initialize should not be called");
            }
        });
        t.ok(true,
             "defining a class does not call the constructor for the class");
    }

    function test_Class_constructor(t) {
        t.plan(7);
        
        var MyClass = OpenLayers.Class({
            prop: null,
            classProp: {'bad': 'practice'},
            initialize: function(a1, a2) {
                this.prop = "instance property";
                t.ok(true,
                     "initialize is called when a new instance is created");
                t.eq(a1, arg1,
                     "initialize is called with the proper first argument");
                t.eq(a2, arg2,
                     "initialize is called with the proper second argument");
            },
            CLASS_NAME: "MyClass"
        });

        var arg1 = "anArg";
        var arg2 = {"another": "arg"};
        var myObj = new MyClass(arg1, arg2);
        t.eq(MyClass.prop, null,
             "creating a new instance doesn't modify the class");
        t.eq(myObj.prop, "instance property",
             "the new instance is assigned a property in the constructor");
        t.eq(myObj["CLASS_NAME"], "MyClass",
             "the new object is an instance of MyClass");

        // allow for modification of class properties
        MyClass.prototype.classProp.bad = "good";
        t.eq(myObj.classProp.bad, "good",
             "modifying a class property modifies properties of the instance");
    }

    function test_Class_inheritance(t) {
        t.plan(7);
        
        var BaseClass = OpenLayers.Class({
            prop: "base",
            initialize: function() {
                t.ok(false,
                     "base class constructor is not called during inheritance");
            },
            toString: function() {
                return "toString inherited";
            },
            CLASS_NAME: "BaseClass"
        });
        
        var ChildClass = OpenLayers.Class(BaseClass, {
            initialize: function() {
                t.ok(true,
                     "child class constructor is called in creating an instance");
            },
            CLASS_NAME: "ChildClass"
        });
        
        var child = new ChildClass();
        t.eq(child.prop, "base",
             "instance of child inherits properties from base");
        t.eq(child.toString(), "toString inherited",
             "instance of child inherits toString method from base");
        t.eq(child["CLASS_NAME"],
             "ChildClass",
             "new object is an instance of the child class");
        
        var F = OpenLayers.Class(Object, {});
        t.ok(!("initialize" in Object.prototype), "no messing with non OL prototypes");

        // test with an abstract class (i.e. a class that doesn't have an initialize
        // method) as the parent class
        var Vehicule = OpenLayers.Class({
            numWheels: null
        });
        var Bike = OpenLayers.Class(Vehicule, {
            initialize: function() {
                this.numWheels = 2;
            }
        });
        var b = new Bike();
        t.ok(b instanceof Vehicule, "a bike is a vehicule");
        
        // test inheritance with something that has a non-function initialize property
        var P = OpenLayers.Class({
            initialize: "foo"
        });
        var C = OpenLayers.Class(P, {
            initialize: function() {
                // pass
            }
        });
        var c = new C();
        t.eq(P.prototype.initialize, "foo", "Class restores custom initialize property.");
        
    }
    
    function test_Class_multiple_inheritance(t) {
        t.plan(7);
        var BaseClass1 = OpenLayers.Class({
            override: "base1",
            prop: "base1",
            variable: null,
            initialize: function() {
                t.ok(true,
                     "only called when an instance of this class is created");
            },
            CLASS_NAME: "BaseClass1"
        });

        var BaseClass2 = OpenLayers.Class({
            override: "base2",
            initialize: function() {
                t.ok(false,
                     "base class constructor is not called during inheritance");
            },
            CLASS_NAME: "BaseClass1"
        });
        
        var ChildClass = OpenLayers.Class(BaseClass1, BaseClass2, {
            initialize: function(arg) {
                if(this.prop == "base1") {
                    this.variable = "child";
                }
                t.ok(true,
                     "only child class constructor is called on initialization");
            },
            CLASS_NAME: "ChildClass"
        });
        
        var arg = "child";
        var child = new ChildClass(arg);
        t.eq(child.variable, arg,
             "inheritance works before construction");
        t.eq(child.prop, "base1",
             "properties are inherited with multiple classes")
        t.eq(child.override, "base2",
             "properties are inherited in the expected order");
        t.eq(child["CLASS_NAME"],
             "ChildClass",
             "object is an instance of child class");
        
        var base1 = new BaseClass1();
        t.eq(base1.override, "base1",
             "inheritance doesn't mess with parents");

    }

    function test_inheritance_chain(t) {
        t.plan(1);
        var A = new OpenLayers.Class({
            initialize: function() {
                this.a = 'foo';
            }
        });
        var B = new OpenLayers.Class(A, {});
        var C = new OpenLayers.Class(B, {
            initialize: function() {
                B.prototype.initialize.apply(this, arguments);
                this.a = this.a + 'bar';
            }
        });
        var c = new C;
        t.eq(c.a, 'foobar', 'constructor at the root is called');
    }
    

    function test_Class_isInstanceOf(t) {
        t.plan(7);
        var wms = new OpenLayers.Layer.WMS({});
        var drag = new OpenLayers.Control.DragFeature({});
        t.ok(wms instanceof OpenLayers.Layer.WMS, "isInstanceOf(WMS)");
        t.ok(wms instanceof OpenLayers.Layer, "isInstanceOf(Layer)");
        t.ok(!(wms instanceof OpenLayers.Format), "not isInstanceOf(Format)");
        t.ok(drag instanceof OpenLayers.Control, "drag is a control");
        t.ok(!(drag instanceof OpenLayers.Layer), "drag is not a layer");

        //test a class with multiple inheritance
        var BadClass=OpenLayers.Class(OpenLayers.Layer.WMS, OpenLayers.Control.DragFeature);
        var bad = new BadClass({});
        t.ok(!(bad instanceof OpenLayers.Control), "bad is a control, but it is also a layer and we cannot have two superclasses");
        t.ok(bad instanceof OpenLayers.Layer, "bad is a layer, it inherits from the layer first");
    }

    //
    // IGN's GeoPortal API overwrite prototypes of OpenLayers constructors.
    // The tests below aim to cover their usage pattens.
    //

    // the overwrite function under test
    function overwrite(C, o) {
        if(typeof o.initialize === "function" &&
            C === C.prototype.initialize) {
            // OL 2.11

            var proto = C.prototype;
            var staticProps = OpenLayers.Util.extend({}, C);

            C = o.initialize;

            C.prototype = proto;
            OpenLayers.Util.extend(C, staticProps);
        }
        OpenLayers.Util.extend(C.prototype, o);
        return C;
    }

    function test_overwrite_1(t) {
        // overwrite constructor
        t.plan(1);
        var A = OpenLayers.Class({
            initialize: function() {
                this.a = "foo";
            }
        });
        A = overwrite(A, {
            initialize: function() {
                this.a = "bar";
            }
        });
        var a = new A;
        t.eq(a.a, "bar", "ctor overwritten");
    }

    function test_overwrite_2(t) {
        // overwrite regular method
        t.plan(1);
        var A = OpenLayers.Class({
            initialize: function() {
            },
            method: function() {
                this.a = "foo";
            }
        });
        A = overwrite(A, {
            method: function() {
                this.a = "bar";
            }
        });
        var a = new A;
        a.method();
        t.eq(a.a, "bar", "method overwritten");
    }

    function test_overwrite_3(t) {
        // overwrite constructor of subclass
        t.plan(1);
        var A = OpenLayers.Class({
            initialize: function() {
                this.a = "foo";
            }
        });
        var B = OpenLayers.Class(A, {
            initialize: function() {
                A.prototype.initialize.call(this);
            }
        });
        B = overwrite(B, {
            initialize: function() {
                A.prototype.initialize.call(this);
                this.a = "bar";
            }
        });
        var b = new B;
        t.eq(b.a, "bar", "ctor overwritten");
    }

    function test_overwrite_4(t) {
        // overwrite constructor of parent class
        t.plan(1);
        var A = OpenLayers.Class({
            initialize: function() {
                this.a = "foo";
            }
        });
        var B = OpenLayers.Class(A, {
            initialize: function() {
                A.prototype.initialize.call(this);
            }
        });
        A = overwrite(A, {
            initialize: function() {
                this.a = "bar";
            }
        });
        var b = new B;
        t.eq(b.a, "bar", "ctor overwritten");
    }

    function test_overwrite_5(t) {
        // overwrite constructor of parent class, which itself
        // doesn't defined "initialize"
        t.plan(2);
        var A = OpenLayers.Class({
            initialize: function() {
                this.a = "foo";
            }
        });
        var B = OpenLayers.Class(A, {});
        var _A = A;
        A = overwrite(A, {
            initialize: function() {
                this.a = "bar";
            }
        });
        var b = new B;
        t.ok(A.prototype === _A.prototype, "A and _A share the prototype");
        t.eq(b.a, "bar", "ctor overwritten");
    }

    function test_overwrite_6(t) {
        // with static methods
        t.plan(1);
        var A = OpenLayers.Class({
            initialize: function() {
            }
        });
        A.staticMethod = function() {};
        A = overwrite(A, {
            initialize: function() {
            }
        });
        var exc = false;
        try {
            A.staticMethod();
        } catch(e) {
            exc = true;
        }
        t.ok(!exc, "static method still there");
    }
  </script>
</head>
<body>
</body>
</html>
